/**
 * Copyright 2023-present DreamNum Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import type { CellValue } from '@univerjs/core';
import type { ISetRangeValuesMutationParams } from '@univerjs/sheets';
import { covertCellValue, covertCellValues, ICommandService } from '@univerjs/core';
import { SetRangeValuesCommand, SetRangeValuesMutation } from '@univerjs/sheets';
import { FWorksheet } from '@univerjs/sheets/facade';

export class FSheetsBindingDataWorksheet extends FWorksheet {
    private IfsetSource = false;
    _updateCellValue(dataPath: string, cellRefOrRange: string): void {
        const _data = this.getCustomMetadata()?.dataSource;
        if (!_data) return;
        const value = this._getValueFromDataSource(dataPath, _data);
        if (value !== undefined && value !== null) {
            if (cellRefOrRange.includes(':') && Array.isArray(value)) {
                const range = this.getRange(cellRefOrRange).getRange();
                const realValue = covertCellValues(value as CellValue[][], range);
                this._commandService.syncExecuteCommand(SetRangeValuesCommand.id, {
                    unitId: this._workbook.getUnitId(),
                    subUnitId: this._worksheet.getSheetId(),
                    range,
                    value: realValue,
                });
            } else {
                const realValue = covertCellValue(value as CellValue);
                this._commandService.syncExecuteCommand(SetRangeValuesCommand.id, {
                    unitId: this._workbook.getUnitId(),
                    subUnitId: this._worksheet.getSheetId(),
                    range: this.getRange(cellRefOrRange).getRange(),
                    value: realValue,
                });
            }
        }
    }

    _getValueFromDataSource(path: string, source: Record<string, unknown>): unknown {
        return path.split('.').reduce<unknown>((obj, key) => {
            if (obj && typeof obj === 'object' && key in (obj as Record<string, unknown>)) {
                return (obj as Record<string, unknown>)[key];
            }
            return undefined;
        }, source);
    }
    // ...existing code...

    setBindingPath(dataPath: string, cellRefOrRange: string): void {
        const _customMetadata = this.getCustomMetadata() || {};
        const _bindings = this.getCustomMetadata()?.bindings || {};
        const _dataSource = this.getCustomMetadata()?.dataSource || {};
        _bindings[dataPath] = cellRefOrRange;
        if (_customMetadata) {
            _customMetadata.bindings = { ..._customMetadata.bindings, ..._bindings };
            this.setCustomMetadata(_customMetadata);
            if (!Object.hasOwn(_dataSource, dataPath)) { this.getDataSource(); }
        }
        if (_dataSource) {
            this._updateCellValue(dataPath, cellRefOrRange);
        }
    }

    setBinding(bindings: Record<string, string>): void {
        const _customMetadata = this.getCustomMetadata() || {};
        let _bindings = this.getCustomMetadata()?.bindings || {};
        const _dataSource = this.getCustomMetadata()?.dataSource || {};
        _bindings = { ..._bindings, ...bindings };
        if (_customMetadata) {
            _customMetadata.bindings = _bindings;
            this.setCustomMetadata(_customMetadata);
            this.getDataSource();
        }
        if (_dataSource) {
            for (const dataPath in _bindings) {
                if (Object.prototype.hasOwnProperty.call(_bindings, dataPath)) {
                    const cellRefOrRange = _bindings[dataPath];
                    this._updateCellValue(dataPath, cellRefOrRange);
                }
            }
        }
    }

    setDataSource(source: Record<string, CellValue | CellValue[][]>): void {
        const _customMetadata = this.getCustomMetadata() || {};
        const _dataSource = source;
        const _bindings = this.getCustomMetadata()?.bindings || {};
        if (_customMetadata) {
            _customMetadata.dataSource = { ..._customMetadata.dataSource, ..._dataSource };
            this.setCustomMetadata(_customMetadata);
            this.IfsetSource = true;
        }
        Object.keys(_bindings).forEach((dataPath) => {
            this.IfsetSource = true;
            const cellRefOrRange = _bindings[dataPath];
            this._updateCellValue(dataPath, cellRefOrRange);
        });
    }

    getDataSource(): Readonly<Record<string, unknown>> | null {
        const _bindings = this.getCustomMetadata()?.bindings || {};
        const _dataSource = this.getCustomMetadata()?.dataSource || {};
        if (_bindings&&!this.IfsetSource) {
            for (const dataPath in _bindings) {
                if (Object.prototype.hasOwnProperty.call(_bindings, dataPath)) {
                    const cellRefOrRange = _bindings[dataPath];
                    if (cellRefOrRange.includes(':')) {
                        // 区域，读取二维数组
                        const range = this.getRange(cellRefOrRange);
                        _dataSource[dataPath] = range.getValues();
                    } else {
                        // 单个单元格
                        const cellValue = this.getRange(cellRefOrRange).getValue() as CellValue;
                        _dataSource[dataPath] = cellValue;
                    }
                }
            }
        }
        this.IfsetSource = false;
        return _dataSource || {};
    }

    loadBindings(): void {
        const _bindings = this.getCustomMetadata()?.bindings || {};
        const _dataSource = this.getCustomMetadata()?.dataSource || {};
        const commandService = this._injector.get(ICommandService);
        commandService.onCommandExecuted((command) => {
            if (command.id === SetRangeValuesMutation.id) {
                const params = command.params as ISetRangeValuesMutationParams;
                if (
                    params.unitId === this._workbook.getUnitId() &&
                    params.subUnitId === this._worksheet.getSheetId() &&
                    params.cellValue && _bindings&&!this.IfsetSource//避免设置数据源被覆盖
                ) {
                    for (const dataPath in _bindings) {
                        if (Object.prototype.hasOwnProperty.call(_bindings, dataPath)) {
                            const cellRefOrRange = _bindings[dataPath];
                            if (cellRefOrRange.includes(':')) {
                                const range = this.getRange(cellRefOrRange);
                                _dataSource[dataPath] = range.getValues();
                            } else {
                                const cellValue = this.getRange(cellRefOrRange).getValue() as CellValue;
                                _dataSource[dataPath] = cellValue;
                            }
                        }
                    }
                }
                this.IfsetSource= false;
                       }
        });
        if (_dataSource && _bindings) {
            Object.keys(_bindings).forEach((dataPath) => {
                const cellRefOrRange = _bindings[dataPath];
                this._updateCellValue(dataPath, cellRefOrRange);
            });
        }
    }

    removeBindingPath(dataPath: string): void {
    const _customMetadata = this.getCustomMetadata() || {};
    const _bindings = this.getCustomMetadata()?.bindings || {};
    const _dataSource = this.getCustomMetadata()?.dataSource || {};

    if (!_bindings.hasOwnProperty(dataPath)) {
        console.warn(`[removeBindingPath] 绑定路径不存在: ${dataPath}`);
        return;
    }
    delete _bindings[dataPath];   
    delete _dataSource[dataPath];  
    if (_customMetadata) {
        _customMetadata.bindings = { ..._bindings };
        _customMetadata.dataSource = { ..._dataSource };
        this.setCustomMetadata(_customMetadata);
    }

    console.log(`[removeBindingPath] 已删除绑定: ${dataPath}`);
}
}

declare module '@univerjs/sheets/facade' {
    interface IWorksheet extends FSheetsBindingDataWorksheet {

    }
}

FWorksheet.extend(FSheetsBindingDataWorksheet);
